package com.dmz.web3;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * java实现默克尔树
 */
public class MerkleTrees {

    // MerkleRoot
    private String root;

    // 交易集合
    private List<String> txList;

    /**
     * 构造方法
     * 初始化所有txid , root设置成""
     */
    public MerkleTrees(List<String> txList) {
        this.txList = txList;
        root = "";
    }

    /**
     * 根据txid动态求出root
     */
    public void merkle_tree() {

        if (txList==null||txList.size()==0){
            return;
        }

        List<String> tempTxList = new ArrayList<>();

//        for (int i = 0; i < this.txList.size(); i++) {
//            tempTxList.add(this.txList.get(i));
//        }
        tempTxList.addAll(txList);

        //不是是否可以直接把参数设置为 txList
        List<String> newTxList = getNewTxList(tempTxList);

        //执行循环，直到只剩下一个hash值
        while (newTxList.size() != 1) {
            newTxList = getNewTxList(newTxList);
        }

        this.root = newTxList.get(0);
    }

    /**
     * 求出上一层所有节点hash
     *
     * @param tempTxList
     * @return
     */
    private List<String> getNewTxList(List<String> tempTxList) {

        List<String> newTxList = new ArrayList<>();
        int index = 0;
        while (index < tempTxList.size()) {
            // left
            String left = tempTxList.get(index);
            index++;
            // right
            String right = "";
            if (index != tempTxList.size()) {
                right = tempTxList.get(index);
            }
            // parent = left + right
            String sha2HexValue = getSHA2HexValue(left + right);
            newTxList.add(sha2HexValue);
            index++;

        }
        return newTxList;
    }

    /**
     * left 、right 求出具体的父类节点hash
     *
     * @param str
     * @return
     */
    public String getSHA2HexValue(String str) {
        byte[] cipher_byte;
        try{
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(str.getBytes());
            cipher_byte = md.digest();
            StringBuilder sb = new StringBuilder(2 * cipher_byte.length);
            for(byte b: cipher_byte) {
                sb.append(String.format("%02x", b&0xff) );
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "";
    }

    /**
     * 获取跟节点hash
     * @return
     */
    public String getRoot() {
        return this.root;
    }

    public static void main(String[] args) {
        List<String> tempTxList = new ArrayList<>();
        tempTxList.add("a");
        tempTxList.add("b");
        tempTxList.add("c");
        tempTxList.add("d");
        tempTxList.add("e");

        MerkleTrees merkleTrees = new MerkleTrees(tempTxList);
        merkleTrees.merkle_tree();

        System.out.println("root : " + merkleTrees.getRoot());

    }
}